﻿// PortableMediator
// (c) Lance Wynn - http://PortableMediator.codeplex.com/
// License: MIT (http://www.opensource.org/licenses/mit-license.php)


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ServiceModel.Dispatcher;
using System.Reflection;
namespace PortableMediator
{
    public interface IMediator
    {
        /// <summary>
        /// Registers an anonymous action to receive publications.
        /// </summary>
        /// <typeparam name="TParam"></typeparam>
        /// <param name="token"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        Task RegisterSubscriber<TParam>(object token, Action<TParam> action);

        /// <summary>
        /// registers an anonymous function to receive publications
        /// (This is removed for now as the func.Target is always null which causes it to immediately die, and it will never 
        /// receive messages)
        /// </summary>
        /// <typeparam name="TParam"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="token"></param>
        /// <param name="target">target where the anonymouse method is declared (this)</param>
        /// <param name="func"></param>
        /// <returns></returns>
        Task RegisterSubscriber<TParam, TResult>(object token, object target, Func<TParam, TResult> func);
        
        /// <summary>
        /// Registers a method by name to receive publications for a specified token
        /// </summary>
        /// <param name="token"></param>
        /// <param name="target"></param>
        /// <param name="method"></param>
        /// <returns></returns>
        Task RegisterSubscriber(object token, object target, string method);

        /// <summary>
        /// Registers a method by the given method info to receive publication.
        /// </summary>
        /// <param name="token"></param>
        /// <param name="target"></param>
        /// <param name="methodInfo"></param>
        /// <returns></returns>
        Task RegisterSubscriber(object token, object target, MethodInfo methodInfo);

        /// <summary>
        /// Registers all methods/properties in the target for publications if they are decorated with the MediatorMessageSink Attribute
        /// </summary>
        /// <param name="target"></param>
        /// <returns></returns>
        Task RegisterSubscriber(object target);

        /// <summary>
        /// publishes a message to subscribers for the given token that are able to receive the given parameter type.
        /// </summary>
        /// <typeparam name="TParam">message parameter type</typeparam>
        /// <param name="token">unique token</param>
        /// <param name="param">parameter</param>
        /// <returns>Task</returns>
        Task PublishMessage<TParam>(object token, TParam param);

        /// <summary>
        /// publishes a message to subscribers for the given token that are able to receive the given parameter type.
        /// </summary>
        /// <typeparam name="TParam">message parameter type</typeparam>
        /// <typeparam name="TResult">expected result type</typeparam>
        /// <param name="token">unique token of message</param>
        /// <param name="param">message parameter</param>
        /// <returns>IEnumerable of TResults, message sinks that do not return a value, or return a value that is not assignable to TResult will still be executed, but will not return a value in the result list.</returns>
        Task<IEnumerable<TResult>> PublishMessageWithReturnResult<TParam, TResult>(object token, TParam param);
        
        /// <summary>
        /// Publishes a two-way message, subscribers that return a value that can be coerced to the TResult type will pass it back to the publisher via the callback action.
        /// </summary>
        /// <typeparam name="TParam">parameter type of the message</typeparam>
        /// <typeparam name="TResult">expected message result type</typeparam>
        /// <param name="token">Message Token</param>
        /// <param name="param">Message Parameter</param>
        /// <param name="callback">Callback action</param>
        /// <returns>Task </returns>
        Task PublishMessage<TParam, TResult>(object token, TParam param, Action<TResult> callback);
    }
}
